#pragma once
#include "log.hpp"
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "ThreadPool.hpp"
#include "Task.hpp"

enum{
    UsageError = 1,
    SockerError,
    BindError,
    ListenError
};
const std::string defaultip = "0.0.0.0";
const int backlog = 10;

Log log{};

class TcpServer;
struct ThreadData
{
    ThreadData(int sockfd, const std::string &clientip, const uint16_t &clientport, TcpServer *tsvr)
        :sockfd_(sockfd), clientip_(clientip), clientport_(clientport), tsvr_(tsvr)
    {}
    int sockfd_;
    std::string clientip_;
    uint16_t clientport_;
    TcpServer *tsvr_;
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port, const std::string &ip = defaultip)
    :listensock_(-1), port_(port), ip_(ip)
    {}
    ~TcpServer()
    {
        if (listensock_) close(listensock_);
    }
    void InitServer()
    {
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            log(Fatal, "create socket err, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SockerError);
        }
        log(Info, "create socket success, listensock: %d",listensock_);

        int opt = 1;
        setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));  // 防止偶发性的服务器无法进行立即重启

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));  // local.sin_addr.s_addr = INADDR_ANY

        if (bind(listensock_, (struct sockaddr*)&local, (socklen_t)sizeof(local)) < 0)
        {
            log(Fatal, "bind err, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        log(Info, "bind success, listensock: %d", listensock_);

        
        if (listen(listensock_, backlog) < 0)
        {
            log(Fatal, "listen err, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        log(Info, "listen success, listensock: %d", listensock_);

    }
    void Start()
    {
        ThreadPool<Task>::GetInstance()->Start();
        log(Info, "tcpserver is running...");
        for(;;)
        {
            // 1. 获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int clientfd = accept(listensock_, (struct sockaddr*)&client, &len);
            if (clientfd < 0)
            {
                log(Warning, "accept err, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));
            log(Info, "get a new lin... sockfd: %d, client ip:port ->  %s:%d", clientfd, clientip, clientport);


            // Version 1 -- 单进程版
            // Service(clientfd, clientip, clientport);
            // close(clientfd);

            // Version 2 -- 多进程版
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     // child
            //     close(listensock_);
            //     if (fork() > 0) exit(0);  // 子进程里在创建孙子进程,然后自身退出,让孙子进程被OS领养,解决僵尸进程问题
            //     Service(clientfd, clientip, clientport);  // 孙子进程,system领养 解决僵尸进程问题  or signal(CHILD, SIG_IGN)方法
            //     close(clientfd);
            //     exit(0);
            // } 

            // Version 3 -- 进程池版本 可能存在安全问题, accept需要加锁

            // Version 4 -- 多线程本本
            // ThreadData *td = new ThreadData(clientfd, clientip, clientport, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            // Version 5 -- 线程池版本
            Task t(clientfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }
    // static void *Routine(void *args)
    // {
    //     pthread_detach(pthread_self());  // 线程分离
    //     ThreadData *td = static_cast<ThreadData*>(args);
    //     td->tsvr_->Service(td->sockfd_, td->clientip_, td->clientport_);
    // }
    // void Service(int sockfd, const std::string &clientip, const uint16_t &clientport)
    // {
    //     char buffer[4096];
    //     while (true)
    //     {
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));
    //         if (n > 0)
    //         {
    //             buffer[n] = 0; 
    //             std::cout << "client say# " << buffer << std::endl;
    //             std::string echo_string = "tcpserver echo# ";
    //             echo_string += buffer;
    //             write(sockfd, echo_string.c_str(), echo_string.size());
    //         }
    //         else if (n == 0)
    //         {
    //             log(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         else
    //         {
    //             log(Warning, "read err, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
    //             break;
    //         }
    //     }
    //     close(sockfd);
    // }
private:
    int listensock_;
    uint16_t port_;
    std::string ip_;
};
